package cn.oi.klittle.era.widget.compat.editText

import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.text.Editable
import android.text.method.HideReturnsTransformationMethod
import android.text.method.PasswordTransformationMethod
import android.util.AttributeSet
import android.view.*
import android.widget.TextView

import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import cn.oi.klittle.era.R
import cn.oi.klittle.era.base.KBaseUi
import cn.oi.klittle.era.comm.kpx
import cn.oi.klittle.era.exception.KCatchException
import cn.oi.klittle.era.helper.KAsteriskPasswordTransformationMethod
import cn.oi.klittle.era.utils.KLoggerUtils
import org.jetbrains.anko.runOnUiThread
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.delay

/**
 * fixme 自定义文本输入框。拷贝了系统的EditText
 * fixme 文本长按默认自带复制黏贴功能。
 */

//fixme 文本框焦点错乱解决方案。文本框如果是布局内的第一个控件，就容易发生异常（系统Bug）。如果不是布局内的第一个控件，一般都不会发生焦点异常。

//fixme 方案一
//在父容器中，添加以下两个属性。一般只要添加 isFocusable=true即可。以防万一，两个属性都加上
//isFocusable=true
//isFocusableInTouchMode=true//fixme 设置了true之后，第一次点击时会聚焦，不会触发点击事件。第二次点击才会触发点击事件（即聚焦之后点击才会触发点击事件。）

//fixme 方案二
//在父容器中，第一个控件。添加如下：

//                view {
//                    isFocusable = true//必不可少
//                }.lparams {
//                    width = 0
//                    height = kpx.x(14)//测试发现，高度必须大于等于kpx.x(14)才有效。宽度无所谓
//                }

//fixme 亲测在控件初始化时，调用requestFocus()获取焦点的时候，软键盘不会弹出。亲测，Activity和Dialoc初始化时获取焦点，软键盘不会弹出。
//fixme 初始化时，软键盘不会弹出。showSoftInput()无法弹出软键盘(还没初始化完成)；调用showSoftInput2()可以弹出软键盘。
//fixme setSoftInputMode_adjustpan_hidden()默认就是这个模式； 初始化未完成(初始化的时候)，调用requestFocus（）聚焦，软键盘不会弹出来。
//fixme setSoftInputMode_adjustResize_hidden()；调用requestFocus（）聚焦软键盘会弹出来，不管是否初始化完成，软键盘都会弹出来。

//fixme 只有初始完成时，调用requestFocus()；软键盘才会弹出；手指点击输入框，软键盘也会弹出。

//requestFocus() 聚焦；clearFocus() 失去焦点。requestFocus_hidden（）聚焦不弹出软键盘。
//KBaseDialog和KBaseActivity还有 setRequestFocus（）共用的聚焦方法。

open class KMyEditText : KTextView {

    constructor(viewGroup: ViewGroup) : super(viewGroup.context) {
        viewGroup.addView(this)//直接添加进去,省去addView(view)
    }

    constructor(context: Context) : super(context) {}

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}

    private var mOnGlobalLayoutListener_foucse: ViewTreeObserver.OnGlobalLayoutListener? = null

    /**
     * fixme 输入框，聚焦；不弹出软键盘(隐藏软键盘)。亲测有效（Activity初始化的时候都有效）。
     * fixme 隐藏软键盘，主要是解决 setSoftInputMode_adjustResize_hidden（）模式。
     */
    fun requestFocus_hidden() {
        if (isOnDestroy) {
            return
        }
        try {
            requestFocus()//聚焦
            hiddenSoftKeyboard()//隐藏软键盘
            //KLoggerUtils.e("width:\t" + width + "\theight:\t" + height)
            if (Build.VERSION.SDK_INT >= 16 && mOnGlobalLayoutListener_foucse != null) {
                viewTreeObserver?.removeOnGlobalLayoutListener(
                        mOnGlobalLayoutListener_foucse
                )//移除监听
            }
            mOnGlobalLayoutListener_foucse = null
            if (width > 0 || height > 0) {
                //宽和高有值，表示布局已经加载完成。
                hideSoftKeyboard2(context, this)//fixme 以防万一
                return
            }
            //fixme 以下是布局还未加载完成；监听完布局，再隐藏软键盘
            //局部变量，不会冲突的。
            mOnGlobalLayoutListener_foucse = ViewTreeObserver.OnGlobalLayoutListener {
                if (Build.VERSION.SDK_INT >= 16 && mOnGlobalLayoutListener_foucse != null) {
                    viewTreeObserver?.removeOnGlobalLayoutListener(
                            mOnGlobalLayoutListener_foucse
                    )//移除监听
                }
                mOnGlobalLayoutListener_foucse = null
                hiddenSoftKeyboard()//fixme 隐藏软键盘(防止不隐藏)
                hideSoftKeyboard2(context, this)//fixme 以防万一（在这里调用，基本上百分百有效。）
                //KLoggerUtils.e("加载完成")
            }
            viewTreeObserver?.addOnGlobalLayoutListener(
                    mOnGlobalLayoutListener_foucse
            )//监听布局加载
        } catch (e: Exception) {
            e.printStackTrace()
            KLoggerUtils.e("KMyEditText聚焦，隐藏软键盘异常：\t" + e.message, isLogEnable = true)
        }
    }

    /**
     * fixme 软键盘交替（亲测可行！）（目前没有判断软键盘是否弹出的方法。）
     */
    fun toggleSoftInput() {
        KMyEditText.toggleSoftInput(context)
    }

    //调出软键盘
    fun showSoftInput() {
        KMyEditText.showSoftInput(context, this)
    }

    //调出软键盘(防止初始化时软键盘调不出，所以延迟一下，再弹出软键盘，亲测有效。)
    fun showSoftInput2() {
        try {
            GlobalScope.async {
                delay(35)//10毫秒足以。
                getContext()?.runOnUiThread {
                    KMyEditText.showSoftInput(this, this@KMyEditText)
                }
            }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
    }

    //调出软键盘(防止初始化时软键盘调不出，所以延迟一下，再弹出软键盘，亲测有效。)
    fun showSoftInput3() {
        try {
            GlobalScope.async {
                delay(135)//fixme 130毫秒,防止无效。这个延迟时间，几乎百分百有效。
                getContext()?.runOnUiThread {
                    KMyEditText.showSoftInput(this, this@KMyEditText)
                }
            }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
    }

    //隐藏软键盘
    fun hiddenSoftKeyboard() {
        KMyEditText.hiddenSoftKeyboard(context, this)
    }

    fun getSoftInputHeight(context: Context?): Int {
        context?.let {
            if (it is Activity) {
                return getSoftInputHeight(it as Activity)
            }
        }
        return 0
    }

    fun getSoftInputHeight(activity: Activity? = KBaseUi.getActivity()): Int {
        if (activity == null) {
            return 0
        }
        if (activity.isFinishing) {
            return 0
        }
        return getSoftInputHeight(activity?.window)
    }

    /**
     * fixme 获取输入高度(不是布局被挤上的高度，就算软键盘的高度。);亲测执行该方法只需1毫秒
     * @param window fixme Activity和Dialog的window是一起。即Dialog弹窗被挤上去，Activity的界面也会被挤上去。（亲测！）
     * @return 大于0，输入法显示，小于等于0，输入发没有弹出
     */
    fun getSoftInputHeight(window: Window?): Int {
        try {
            if (window == null) {
                return 0
            }
            var barHeight = kpx.navigationBarHeight//低部导航栏的高度
            //获取当前屏幕内容的高度
            var screenHeight = kpx.maxScreenHeight() - barHeight;
            //获取View可见区域的bottom
            var rect = Rect();
            window.getDecorView().getWindowVisibleDisplayFrame(rect);//fixme getWindowVisibleDisplayFrame()获取得到的是最外层控件的位置。不是本控件。
            //activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
            //KLoggerUtils.e("screenHeight:\t" + screenHeight + "\tbottom:\t" + rect.bottom + "\t结果：\t" + (screenHeight - rect.bottom))
            //(screenHeight - rect.bottom) fixme 非全屏幕下正常；0软键盘没有显示；大于0，软键盘显示，该差值就算软键盘的高度。一般为764
            //fixme 全面屏模式下；-130(低部导航栏的高度)软键盘没有显示；软键盘显示时，软键盘的高度大约为771和正常的差不多。
            var inputHeight = (screenHeight - rect.bottom);//低部导航栏的高度一般都为130；输入法高度一般为764
            inputHeight?.let {
                if (it > barHeight) {
                    return it//fixme 返回输入高度（不是布局被挤的高度，就是软键盘的高度）
                } else {
                    return 0//fixme 为0，软键盘没有显示。
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return 0
    }

    /**
     * fixme 设置光标宽度和颜色【8.0和9.0两个版本无效，其他都有效。】
     * @param color 光标颜色
     * @param size 光标宽度。（大于0才设置，小于等于0。默认设置1dp。）
     */
    fun setCursorColor(color: Int, size: Int = 0) {
        try {
            if (Build.VERSION.SDK_INT <= 26) {
                //只对8.0以下有效果
                var fCursorDrawableRes = TextView::class.java.getDeclaredField("mCursorDrawableRes")//获取这个字段
                fCursorDrawableRes.setAccessible(true)//代表这个字段、方法等等可以被访问
                var mCursorDrawableRes = fCursorDrawableRes.getInt(this)

                var fEditor = TextView::class.java.getDeclaredField("mEditor");
                fEditor.setAccessible(true);
                var editor = fEditor.get(this)

                var clazz = editor::class.java
                var fCursorDrawable = clazz.getDeclaredField("mCursorDrawable");
                fCursorDrawable.setAccessible(true);

                val drawables = arrayOfNulls<Drawable>(2)
                drawables[0] = getContext().getResources().getDrawable(mCursorDrawableRes);
                drawables[1] = getContext().getResources().getDrawable(mCursorDrawableRes);
                drawables[0]?.setColorFilter(color, PorterDuff.Mode.SRC_IN);//SRC_IN 上下层都显示。下层居上显示。
                drawables[1]?.setColorFilter(color, PorterDuff.Mode.SRC_IN);
                fCursorDrawable.set(editor, drawables);
            } else if (Build.VERSION.SDK_INT >= 29) {
                //fixme 只对android 10及以上有效
                //KLoggerUtils.e("textCursorDrawable:\t" + textCursorDrawable)
                //fixme textCursorDrawable默认是不为空的。
                if (textCursorDrawable == null) {
                    setTextCursorDrawable(R.drawable.kera_drawable_edit_cursor_color)//fixme 这个获取的Drawable能够转化为GradientDrawable
                }
                textCursorDrawable?.let {
                    if (!(it is GradientDrawable)) {
                        setTextCursorDrawable(R.drawable.kera_drawable_edit_cursor_color)
                    }
                }
                textCursorDrawable?.let {
                    if (it is GradientDrawable) {
                        it.setColor(color)
                        if (size > 0) {
                            it.setSize(size, textSize.toInt())
                        }
                    }
                }
            }
        } catch (e: Exception) {
            //Log.e("test", "光标颜色设置异常")
            KLoggerUtils.e("光标颜色设置异常:\t" + KCatchException.getExceptionMsg(e), true)
        }
    }

    //内容清除
    fun clear() {
        setText(null)
    }

    override fun onDestroy() {
        super.onDestroy()
        textWatcher = null
        if (Build.VERSION.SDK_INT >= 16 && mOnGlobalLayoutListener_foucse != null) {
            viewTreeObserver?.removeOnGlobalLayoutListener(
                    mOnGlobalLayoutListener_foucse
            )//移除监听
        }
        mOnGlobalLayoutListener_foucse = null
    }

    companion object {

        /**
         * fixme 手动调出软键盘,这个文本框不会主动弹出，需要手动调用。所以不需要担心输入框自动弹出的问题。
         * @param view 当前聚焦的View,必不可少
         */
        fun showSoftInput(context: Context?, view: View?) {
            try {
                if (context != null && context is Activity && !context.isFinishing && view != null) {
                    context?.runOnUiThread {
                        try {
                            if (context != null && context is Activity && !context.isFinishing && view != null) {
                                var inputManager: InputMethodManager? = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                                inputManager?.showSoftInput(view, 0)
                                inputManager = null
                            }
                        } catch (e: Exception) {
                            e.printStackTrace()
                            KLoggerUtils.e("软键盘弹出异常:\t" + e.message, isLogEnable = true)
                        }
                    }
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }

        /**
         * fixme 强制隐藏软键盘(有效)
         * @param activity
         */
        fun hiddenSoftKeyboard(context: Context?, view: View? = null) {
            try {
                if (context != null && context is Activity && !context.isFinishing) {
                    context?.runOnUiThread {
                        if (context != null && context is Activity && !context.isFinishing) {
                            try {
                                var inputManager: InputMethodManager? = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                                // (context as Activity).getCurrentFocus()?.getWindowToken() Dialog可能会为空。
                                (context as Activity).getCurrentFocus()?.getWindowToken()?.let {
                                    inputManager?.hideSoftInputFromWindow(it, InputMethodManager.RESULT_UNCHANGED_SHOWN); //强制隐藏键盘
                                }
                                view?.windowToken?.let {
                                    //fixme 这个能解决Dialog弹窗上面，软键盘不消失的问题。亲测。
                                    inputManager?.hideSoftInputFromWindow(it, InputMethodManager.RESULT_UNCHANGED_SHOWN)
                                }
                            } catch (e: Exception) {
                                e.printStackTrace()
                                KLoggerUtils.e("软键盘关闭异常:\t" + KCatchException.getExceptionMsg(e), isLogEnable = true)
                            }
                        }
                    }
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }

        /**
         * fixme 强制隐藏软键盘(有效);防止无效。所以加了延迟。在KBaseDialog弹窗关闭的时候会调用。
         * @param activity
         */
        fun hideSoftKeyboard2(context: Context?, view: View? = null) {
            //fixme 基本上都能关闭软键盘，极少数异常下可能会失败，忽略不计。
            if (context != null && context is Activity && !context.isFinishing) {
                GlobalScope.async {
                    try {
                        hiddenSoftKeyboard(context, view)
                        delay(60)//fixme 防止无效果，至少需要间隔9毫秒才有效。
                        hiddenSoftKeyboard(context, view)
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }
        }

        /**
         * fixme 软键盘交替（亲测可行！）（目前没有判断软键盘是否弹出的方法。）
         */
        fun toggleSoftInput(context: Context?) {
            try {
                if (context != null && context is Activity && !context.isFinishing) {
                    var inputManager: InputMethodManager? = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    inputManager?.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0)//软键盘弹出消失交替（没有软键盘会弹出，有软键盘会消失）
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }

    }
}
